//
// SpheresView.m
//
// Revised for NS3.0 20 Oct 1992
// Matt Pharr- pharr@cs.yale.edu
//

#import "SpheresView.h"
#import "SpheresWrap.c"
#import <appkit/appkit.h>
#import <defaults/defaults.h>
#import <dpsclient/wraps.h>
#import <libc.h>
#import <stdlib.h>

#define MAXSIZE		125
#define SHOW_FILLS  	1
#define DONT_SHOW_FILLS	0

@implementation SpheresView

- oneStep
{
    float red= 0.0, green= 0.0, blue= 0.0;
    float color= 0.0;
    NXPoint position;
    NXPoint hilight;
    int radius= 100;
    float dx= 0.0, dy= 0.0;
    float dcolor= 0.0;
    float dred= 0.0, dgreen= 0.0, dblue= 0.0;
	
    if (++nDrawn >= nSpheres) {
        usleep(1000000);
        nDrawn= 0;
        PSsetgray(0.0);
        NXRectFill(&bounds);
    }
    
    /* decide where to put the sphere after we draw it.. */
    position.x= (int)randBetween(bounds.origin.x - MAXSIZE / 2, 
                                 bounds.origin.x + bounds.size.width - MAXSIZE/2);
    position.y= (int)randBetween(bounds.origin.y - MAXSIZE / 2, 
                                 bounds.origin.y + bounds.size.height - MAXSIZE/2);

    radius= (int)randBetween(30, MAXSIZE);

    /* where to put the hilight on the sphere- always in the same relative
       place */
    hilight.x= .4 * radius;
    hilight.y= .6 * radius;

    /* distance by which we need to move each time when drawing the big highlight.
       basically what we do is start at the position of the hilight and draw a little
       circle that is all white there. Then we move out away from there and draw
       bigger and bigger circles that become darker and darker, until they hit the
       color we pick for the sphere below. This gives us the 3-d shading effect.
       Actually, though, we do the above in reverse, so as not to draw over the 
       circles- we're actually drawing smaller and smaller concentric, filled circles.
       N.B. there's probably a more efficient way to do this...
       */
	
    dx= hilight.x / radius;
    dy= hilight.y / radius;

    if ([Window defaultDepthLimit] == NX_TwoBitGrayDepth) {
        /* Black and White machines */
        color= randBetween(0.0, .4);
        dcolor= (1 - color) / radius;
    }
	
    else { 
        red= randBetween(0.0, .4);
        dred= (1 - red) / radius;
		
        green= randBetween(0.0, .4);
        dgreen= (1 - green) / radius;

        blue= randBetween(0.0, .4);
        dblue= (1 - blue) / radius;
    }

	
    if (showFills == NO) {
        if ([myImage lockFocus] == YES) {
            /* clear out the NXImage, but leave a transparent background, so when we
               draw it on the screen below, the square in which the sphere is drawn doesn't
               cover up other spheres on the screen unless we have actively drawn in
               the bitmap first...
               */
			
            PSsetgray(0.0);
            PSsetalpha(0.0);
            NXRectFill(&bounds);
			
            if ([Window defaultDepthLimit] == NX_TwoBitGrayDepth) {
                /* draw a sphere in black and white... */
                drawSphereBW(color, radius, dcolor, dx, dy, MAXSIZE);
            }
            else {
                /* or in color... */
                drawSphereCL(red, green, blue, radius, dred, dgreen, dblue, dx, dy, MAXSIZE);
            }
			
            [myImage unlockFocus];
            /* and put it on the screen... */
            [myImage composite:NX_SOVER toPoint:&position];
        }
    }
	
    if (showFills == YES) {
        NXRectClip(&bounds);
        /* need to do this for drawing it in a normal window... */
	
        PStranslate(position.x, position.y);
		
        if ([Window defaultDepthLimit] == NX_TwoBitGrayDepth) {
            /* draw a sphere in black and white... */
            drawSphereBW(color, radius, dcolor, dx, dy, MAXSIZE);
        }
        else {
            /* or in color... */
            drawSphereCL(red, green, blue, radius, dred, dgreen, dblue, dx, dy, MAXSIZE);
        }
			
        PStranslate(-position.x, -position.y);
    }

    return self;
}


- initFrame:(const NXRect *)frameRect
{
    NXSize imageSize;
	
    [super initFrame:frameRect];

    [self inspector:self];

    if ((NXGetDefaultValue([NXApp appName], "sphereNumber") == NULL) ||
        (NXGetDefaultValue([NXApp appName], "sphereShowFill") == NULL)) {
        NXWriteDefault([NXApp appName], "sphereNumber", "50");
        nSpheres= 50;
        NXWriteDefault([NXApp appName], "sphereShowFill", "NO");
        showFills= NO;
    }
    else {
        nSpheres= atoi(NXGetDefaultValue([NXApp appName], "sphereNumber"));
        if (strcmp(NXGetDefaultValue([NXApp appName], "sphereShowFill"), "YES") == 0) {
            showFills= YES;
        }
        else {
            showFills= NO;
        }
    }

    [theSlider setIntValue:nSpheres];
    [theSlider update];
	
    if (showFills == YES) {
        [checkBox setState:SHOW_FILLS];
    }
    else {
        [checkBox setState:DONT_SHOW_FILLS];
    }
    [checkBox update];
	
	
    imageSize.width= 2 * MAXSIZE;
    imageSize.height= 2 * MAXSIZE;
    myImage= [[NXImage alloc] initSize:&imageSize];
	
    nDrawn= 0;
	
    return self;
}


- drawSelf:(const NXRect *)rects :(int)rectCount
{
    if (!rects || !rectCount) {
        return self;
    }

    PSsetgray(0.0);
    NXRectFill(rects);

    return self;
}


- (const char *)windowTitle
{
    return "Spheres";
}


- inspector:sender
{
    char buf[MAXPATHLEN];

    if (!sharedInspectorPanel) {
        sprintf(buf,"%s/%s",[(BSThinker()) moduleDirectory:"Spheres"],"Spheres.nib");
        [NXApp loadNibFile:buf owner:self withNames:NO];
    }

    return sharedInspectorPanel;
}


-setNumber:sender
{
    char temp[20];
	
    nSpheres= [sender intValue];
	
    sprintf(temp, "%d", nSpheres);
    NXWriteDefault([NXApp appName], "sphereNumber", temp);

    return self;
}


-setShowFills:sender
{
    if ([sender state] == SHOW_FILLS) {
        showFills= YES;
        NXWriteDefault([NXApp appName], "sphereShowFill", "YES");
    }
    else {
        showFills= NO;
        NXWriteDefault([NXApp appName], "sphereShowFill", "NO");
    }
	
    return self;
}


@end

